#include <errno.h>		/* error numbers */
#include <sys/ioctl.h>          /* ioctls */
#include <net/if.h>             /* generic interface structures */
#include "unp.h"
#include "hw_addrs.h"
#define IP_SIZE 4

char my_ip_addr[IP_SIZE] = {0};
char my_mac_addr[IF_HADDR] = {0};
int my_if_index = 0;

struct hwa_info *
get_hw_addrs()
{
	struct hwa_info	*hwa, *hwahead, **hwapnext;
	int		sockfd, len, lastlen, alias;
	char		*ptr, *buf, lastname[IF_NAME], *cptr;
	struct ifconf	ifc;
	struct ifreq	*ifr, ifrcopy;
	struct sockaddr	*sinptr;

	sockfd = Socket(AF_INET, SOCK_DGRAM, 0);

	lastlen = 0;
	len = 100 * sizeof(struct ifreq);	/* initial buffer size guess */
	for ( ; ; ) {
		buf = (char*) Malloc(len);
		ifc.ifc_len = len;
		ifc.ifc_buf = buf;
		if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
			if (errno != EINVAL || lastlen != 0)
				err_sys("ioctl error");
		} else {
			if (ifc.ifc_len == lastlen)
				break;		/* success, len has not changed */
			lastlen = ifc.ifc_len;
		}
		len += 10 * sizeof(struct ifreq);	/* increment */
		free(buf);
	}
	hwahead = NULL;
	hwapnext = &hwahead;
	lastname[0] = 0;
	for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
		ifr = (struct ifreq *) ptr;
		len = sizeof(struct sockaddr);
		ptr += sizeof(ifr->ifr_name) + len;	/* for next one in buffer */
		alias = 0; 
		hwa = (struct hwa_info *) Calloc(1, sizeof(struct hwa_info));
		memcpy(hwa->if_name, ifr->ifr_name, IF_NAME);		/* interface name */
		hwa->if_name[IF_NAME-1] = '\0';
				/* start to check if alias address */
		if ( (cptr = (char *) strchr(ifr->ifr_name, ':')) != NULL)
			*cptr = 0;		/* replace colon will null */
		if (strncmp(lastname, ifr->ifr_name, IF_NAME) == 0) {
			alias = IP_ALIAS;
		}
		memcpy(lastname, ifr->ifr_name, IF_NAME);
		ifrcopy = *ifr;
		*hwapnext = hwa;		/* prev points to this new one */
		hwapnext = &hwa->hwa_next;	/* pointer to next one goes here */

                hwa->ip_alias = alias;		/* alias IP address flag: 0 if no; 1 if yes */                    

                sinptr = &ifr->ifr_addr;
                hwa->ip_addr = (struct sockaddr *) Calloc(1, sizeof(struct sockaddr));
                memcpy(hwa->ip_addr, sinptr, sizeof(struct sockaddr));	/* IP address */
                Ioctl(sockfd, SIOCGIFHWADDR, &ifrcopy);	/* get hw address */
                memcpy(hwa->if_haddr, ifrcopy.ifr_hwaddr.sa_data, IF_HADDR);
                Ioctl(sockfd, SIOCGIFINDEX, &ifrcopy);	/* get interface index */
                memcpy(&hwa->if_index, &ifrcopy.ifr_ifindex, sizeof(int));
                
                if(!strncmp(hwa->if_name, "eth0", 4)) {
                        if(hwa->ip_alias != IP_ALIAS) {
                                /* Store the MAC address, IP address and interface index
                                */
                                memcpy(my_mac_addr, hwa->if_haddr, IF_HADDR);
                                my_if_index = hwa->if_index;
                
                        }
                }

        }
        free(buf);
        return(hwahead);	/* pointer to first structure in linked list */
}

void
free_hwa_info(struct hwa_info *hwahead)
{
        struct hwa_info	*hwa, *hwanext;

        for (hwa = hwahead; hwa != NULL; hwa = hwanext) {
                free(hwa->ip_addr);
                hwanext = hwa->hwa_next;	/* can't fetch hwa_next after free() */
                free(hwa);			/* the hwa_info{} itself */
        }
}
/* end free_hwa_info */

struct hwa_info *
Get_hw_addrs()
{
        struct hwa_info	*hwa;

        if ( (hwa = get_hw_addrs()) == NULL)
                err_quit("get_hw_addrs error");
        return(hwa);
}

void print_hw_addrs(void)
{
        struct hwa_info	*hwa, *hwahead;
        struct sockaddr	*sa;
        char   *ptr;
        int    i, prflag;

        printf("\nList of interface(s)\n");
        printf("--------------------\n");

        for (hwahead = hwa = Get_hw_addrs(); hwa != NULL; hwa = hwa->hwa_next) {

                if(!strncmp(hwa->if_name, "eth0", 4)) {
                        printf("%s :%s", hwa->if_name, ((hwa->ip_alias) == IP_ALIAS) ? " (alias)\n" : "\n");

                        if ( (sa = hwa->ip_addr) != NULL) {
                                printf("         IP addr = %s\n", Sock_ntop_host(sa, sizeof(*sa)));
                                if(hwa->ip_alias != IP_ALIAS) {
                                        /* Store the MAC address, IP address and interface index
                                        */
                                        struct sockaddr_in  *sin = (struct sockaddr_in *) sa;
                                        memcpy(my_ip_addr, &sin->sin_addr, 4);
                                        // printf("\nDEBUG: my_if_index = %d\n", my_if_index);
                                        // printf("DEBUG: my_mac_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", (unsigned char)my_mac_addr[0], (unsigned char)my_mac_addr[1],
                                        // (unsigned char)my_mac_addr[2], (unsigned char)my_mac_addr[3], (unsigned char)my_mac_addr[4], (unsigned char)my_mac_addr[5]);
                                        // printf("DEBUG: my_ip_addr = %s\n\n", Sock_ntop_host(sa, sizeof(*sa)));
                                        // printf("         HW addr = %02x:%02x:%02x:%02x:%02x:%02x\n", (unsigned char)my_mac_addr[0], (unsigned char)my_mac_addr[1],
                                        //       (unsigned char)my_mac_addr[2], (unsigned char)my_mac_addr[3], (unsigned char)my_mac_addr[4], (unsigned char)my_mac_addr[5]);
                                        // printf("         Interface index = %d\n\n", hwa->if_index);
                                        // continue;
                                }
                        }
                        prflag = 0;
                        i = 0;
                        do {
                                if (hwa->if_haddr[i] != '\0') {
                                        prflag = 1;
                                        break;
                                }
                        } while (++i < IF_HADDR);

                        if (prflag) {
                                printf("         HW addr = ");
                                ptr = hwa->if_haddr;
                                i = IF_HADDR;
                                do {
                                        printf("%.2x%s", *ptr++ & 0xff, (i == 1) ? " " : ":");
                                } while (--i > 0);
                        }

                        printf("\n         Interface index = %d\n\n", hwa->if_index);
                }
        }

        free_hwa_info(hwahead);
}

void get_src_mac(char *mac_addr)
{
        memcpy(mac_addr, my_mac_addr, IF_HADDR);
}

